Skip to main content

Web Templates

Calendar

Source
{% extends 'Layout 1 Column Wide' %}

{% block header %}
{% include 'Breadcrumbs' %}
{% endblock %}

{% block main %}

{% include 'WrapperAJAX' %}

{% assign CalendarContactID = user.id %}

{% include 'Calendar - Charts' %}

{% include 'Calendar - Setup' %}

{% include 'Calendar - Connections' %}

{% if user.roles contains "Calendar Contact" %}
{% include 'Calendar - Contact' %}

{% include 'Calendar - Modals' %}

{% include 'Calendar - JavaScript' %}
{% endif %}

{% include 'Utilities' %}
<style>
#WeekViewToggleButton{
display:none;
}
</style>

{% endblock %}

Calendar - Charts

Source
{% fetchxml countriesWorkedIn %}
<fetch aggregate="true">
<entity name="tt_calendar">
<attribute name="tt_contact" alias="tt_contact" groupby="true" />
<attribute name="tt_locationcountry" alias="tt_locationcountry" groupby="true" />
<attribute name="tt_daytype" alias="tt_daytype" groupby="true" />
<attribute name="tt_calendarid" alias="tt_calendarid_count" aggregate="countcolumn" />
<order alias="tt_contact" />
<order alias="tt_locationcountry" />
<order alias="tt_daytype" />
<filter type="and">
<condition attribute="tt_contact" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
<condition attribute="tt_daytype" operator="eq" value="206340000" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% assign countryList = "" %}
{% assign countryCountList = "" %}

{% if countriesWorkedIn.results.entities.size >= 1 %}
{% assign records = countriesWorkedIn.results.entities.size | minus: 1 %}
{% for i in (0...records) %}
{% assign countryname = countriesWorkedIn.results.entities[i].tt_locationcountry.name %}
{% assign countWorked = countriesWorkedIn.results.entities[i].tt_calendarid_count | string %}

{% assign countryList = countryList | append:',' | append: countryname %}
{% assign countryCountList = countryCountList | append:',' | append: countWorked %}
{% endfor %}
{% endif %}

{% assign countryList = countryList | remove_first: "," %}
{% assign countryCountList = countryCountList | remove_first: "," %}

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>


<!--
<h3>Days Worked in each Country</h3>
<canvas id="myChart" style="max-width: 500px; max-height: 250px;"></canvas>
-->

<script language="javascript">
//BAR CHART
var countries = "{{countryList}}";
var countriesList = countries.split(",");
var workedDays = "{{countryCountList}}";
var workedDaysList = workedDays.split(",");

var ctxchart = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctxchart, {
type: 'bar',
data: {
labels: countriesList,
datasets: [{
label: "Days Worked",
data: workedDaysList,
backgroundColor: [
'rgba(237, 21, 26, 0.4)',
'rgba(95, 95, 97, 0.4)',
'rgba(244, 91, 29, 0.4)',
'rgba(250, 162, 32, 0.4)'
],
borderColor: [
'rgba(237, 21, 26, 1.0)',
'rgba(95, 95, 97, 1.0)',
'rgba(244, 91, 29, 1.0)',
'rgba(250, 162, 32, 1.0)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>

Calendar - Connections

Source
{% comment %} Retrieve Calendar Data Approver & Data Provider Connections {% endcomment %}
{% fetchxml connections %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="contact">
<attribute name="fullname" />
<attribute name="emailaddress1" />
<attribute name="tt_clientcode" />
<attribute name="tt_managername" />
<attribute name="ownerid" />
<attribute name="contactid" />
<order attribute="fullname" descending="false" />
<link-entity name="connection" from="record2id" to="contactid" link-type="inner" alias="av">
<filter type="and">
<filter type="or">
<condition attribute="record2roleidname" operator="eq" value="Calendar - Data Approver" />
<condition attribute="record2roleidname" operator="eq" value="Calendar - Data Provider" />
</filter>
</filter>
<link-entity name="contact" from="contactid" to="record1id" link-type="inner" alias="aw">
<filter type="and">
<condition attribute="contactid" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>
{% endfetchxml %}

{% comment %} Display a Link to a Contacts Calendar where the logged in contact is a Calendar Data Approver or Data Provider {% endcomment %}
{% if connections.results.entities.size > 0 %}
<div>
<h1 style="font-weight:bold;">Shared Calendar Access</h1>
Contacts that you have shared calendar access with are listed below. Select a contact to view their Calendar.
</div>
<div id="contactList" style="text-align: -webkit-center;">
<ul class="nav nav-pills nav-justified" style="width:90%;">
{% assign connectedContacts = connections.results.entities.size | minus: 1 %}
{% for i in (0...connectedContacts) %}
{% assign contactName = connections.results.entities[i].fullname %}
{% assign contactID = connections.results.entities[i].contactid %}
<li role="presentation" style="padding:2px;">
<a href="Shared/?id={{contactID}}">{{contactName}}</a>
</li>
{% endfor %}
</ul>
</div>
<br>
{% endif %}

Calendar - Contact

Source
{% comment %} Information {% endcomment %}
{{snippets["Calendar/Information"]}}

<h1 style="font-weight:bold;"> My Calendar </h1>

<div id="calendarGrid">
{% comment %} Action Buttons for Calendar {% endcomment %}
<div class="btn-group pull-right">
<a id="addNew" class="btn btn-primary" title="Add New" role="button" onclick="SelectModal(null,null)">Add New</a>
<a id="startButton" class="btn btn-primary" title="Add Working Period" role="button" onclick="setUpWorkingPattern()">Add Working Period</a>
<a id="submissionButton" class="btn btn-primary" title="Submit Dates" role="button" onclick="SubmitDatesForm()">Submit Dates</a>
<a id="deletionButton" class="btn btn-secondary" title="Delete" role="button" onclick="DeleteDatesForm()">Delete</a>
</div>

<div class="btn-group pull-right" style="padding-right: 5%;">
<a id="tt_calendarHelp" class="btn btn-info" style="padding:5px 5px;font-size:20px;line-height:1;border-radius:10px;" onclick="$('#calendarHelpBox').show()">
<span class="glyphicon glyphicon-info-sign"></span>
</a>
</div>

<br>

{% include "entity_list" key:"Contact Calendar - Calendar View" %}

</div>

Calendar - JavaScript

Source
{% comment %} Get Form GUIDS from ContentSnippets {% endcomment %}
{% assign createForm = snippets["Calendar/createForm"] %}
{% assign editForm = snippets["Calendar/editForm"] %}
{% assign setupForm = snippets["Calendar/setupForm"] %}
{% assign submissionForm = snippets["Calendar/submissionForm"] %}
{% assign deletionForm = snippets["Calendar/deletionForm"] %}

{% comment %} Get Flow API Url ContentSnippets {% endcomment %}
{% assign submissionUrl = snippets["PracticeGateway/Config/CalendarSubmissionAPI"] %}
{% assign refreshPowerBIUrl = snippets["PracticeGateway/Config/RefreshPowerBIAPI"] %}

<script language="javascript">
//Set Form GUIDS in JS
var createForm = "{{createForm}}";
var editForm = "{{editForm}}";
var setupForm = "{{setupForm}}";
var submissionForm = "{{submissionForm}}";
var deletionForm = "{{deletionForm}}";

$( document ).ready(function() {
var unitedKingdomid = "{{unitedKingdomID}}";
var unitedKingdomname = "{{unitedKingdomName}}";
if(unitedKingdomid != null){
localStorage.setItem("unitedKingdom", unitedKingdomid);
localStorage.setItem("unitedKingdomname", unitedKingdomname);
}
});

async function GetDataFromDataverse(entityLogicalName, fetchxml)
{
return new Promise((resolve) => {
var encodedFetchXML = encodeURI(fetchxml)
var numberofsubmittedRecords = 0;
webapi.safeAjax({
type: "GET",
url: "/_api/" + entityLogicalName + "?fetchXml=" + encodedFetchXML,
contentType:"application/json",
success: function(res) {
setTimeout(() => {
console.log(res.value);
resolve(res.value);
}, 10);
}
});
});
};

async function AddDataToDataverse(entityLogicalName, payload)
{
return new Promise((resolve) => {
webapi.safeAjax({
type: "POST",
url: "/_api/" + entityLogicalName,
contentType: "application/json",
data: JSON.stringify(payload),
success: function(res, status, xhr) {
setTimeout(() => {
resolve("Record Has Been Created");
}, 10);
}
});
});
};

async function DeleteFromDataverse(entityLogicalName, recordID)
{
return new Promise((resolve) => {
webapi.safeAjax({
type: "DELETE",
url: "/_api/" + entityLogicalName + "("+ recordID + ")",
contentType:"application/json",
success: function(res) {
setTimeout(() => {
resolve("Record Has Been Deleted");
}, 10);
}
});
});
};

async function SubmitCalendarRecordsDataverse(entityLogicalName, recordID)
{
var submitted = 206340001;
var inactive = 1

return new Promise((resolve) => {
webapi.safeAjax({
type: "PATCH",
url: "/_api/" + entityLogicalName + "(" + recordID + ")",
contentType: "application/json",
data: JSON.stringify({
"statecode": inactive,
"statuscode": submitted
}),
success: function (res) {
setTimeout(() => {
resolve("Record Has Been Submitted");
}, 10);
}
});
});
};


async function GiveMeRecords(startDate,endDate,monday,tuesday,wednesday,thursday,friday,saturday,sunday,workingHours,country,state,city,overwriteData)
{

let iframeid = 'setupFrame'
let iframelogid = "workingPeriodLog"
let overwiteresponse = false;
if(overwriteData) {
console.log("calling function: overwriteExistingData - GiveMeRecords");
overwiteresponse = await overwriteExistingData(startDate, endDate, iframeid, iframelogid)
console.log("function completed: overwriteExistingData - GiveMeRecords");
}
if( !overwriteData || overwiteresponse == true ) {

var iframe = document.getElementById(iframeid);
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var workingPeriodLog = $(iframeDocument).find('span[id="' + iframelogid + '"]');
var eventType = 206340000;
var contactid = "{{CalendarContactID}}";

//Day Types
var working = 206340000;
var nonworking = 206340001;
var absence = 206340002;
var annualLeave = 206340003;
var travelling = 206340004;
var other = 206340005;
var maternityLeave = 206340006;
var inCountryAtMidnight = true;

//Status Code
var submitted = 206340001;

var oneDayInSeconds = 86400000;

let end = Date.parse(endDate)
end = end.getTime() / oneDayInSeconds;
let current = Date.parse(startDate)
current = current.getTime() / oneDayInSeconds

var remainder = end - current;
var datesToAdd = [];
workingPeriodLog.text(`Validating days to create.`);
for(var d = Date.parse(startDate); d <= Date.parse(endDate); d.setDate(d.getDate()+ 1))
{
let start = Date.parse(d)
var formattedstartDate = Date.parse(start).format("MM/dd/yyyy")
//Add to Dates to Add array
datesToAdd.push(formattedstartDate);
workingPeriodLog.text(`Checking for already submitted dates in selected range.`);

var fetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<attribute name='statuscode' />
<attribute name='tt_startdate' />
<attribute name='tt_workinghours' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + formattedstartDate + `' />
<condition attribute='statuscode' operator='eq' value='` + submitted + `' />
<filter type='or'>
<condition attribute='tt_daytype' operator='ne' value='` + travelling + `' />
<condition attribute='statuscode' operator='eq' value='` + submitted + `' />
</filter>
</filter>
</entity>
</fetch>`

const fetchResult = await GetDataFromDataverse("tt_calendars", fetchxml);

var numberofsubmittedRecords = fetchResult.length;
remainder--;

if(numberofsubmittedRecords > 0)
{
var resultDate = Date.parse(fetchResult[0].tt_startdate).format("MM/dd/yyyy")
let index = datesToAdd.indexOf(resultDate);

if (index !== -1) {
// Remove the element at the found index
datesToAdd.splice(index, 1);
}
}
workingPeriodLog.text(`Creating records.`);
if(remainder < 0)
{
if(datesToAdd.length == 0)
{
window.top.location.reload();
}
var recordsToAdd = datesToAdd.length;
for(var x = 0; x < recordsToAdd; x++)
{
workingPeriodLog.text(`${x} out of ${recordsToAdd} days added.`);
var recordDate = Date.parse(datesToAdd[x]).format("yyyy-MM-ddT10:00:00.0000000")
var y = Date.parse(datesToAdd[x]);
var dayType = nonworking;
switch(y.getDay()){
case 0: //Sunday set dayType to Non-Working
if(sunday){ dayType = working; }
break;
case 1: //Monday
if(monday){ dayType = working; }
break;
case 2: //Tuesday
if(tuesday){ dayType = working; }
break;
case 3: //Wednesday
if(wednesday){ dayType = working; }
break;
case 4: //Thursday
if(thursday){ dayType = working; }
break;
case 5: //Friday
if(friday){ dayType = working; }
break;
case 6: //Saturday
if(saturday){ dayType = working; }
break;
}

var payload = {
"tt_LocationCountry@odata.bind": "/tt_countries(" + country + ")",
"tt_eventtype" : eventType,
"tt_startdate": recordDate,
"tt_enddate": recordDate,
"tt_Contact@odata.bind": "/contacts(" + contactid + ")",
"tt_incountryatmidnight" : inCountryAtMidnight,
"tt_daytype": dayType
}

if(dayType == working) //Working
{
payload["tt_workinghours"] = workingHours;
}

if(state != "" && state != null)
{
payload["tt_LocationState@odata.bind"] = "/tt_states(" + state + ")";

if(city != "" && city != null)
{
payload["tt_LocationCity@odata.bind"] = "/tt_cities(" + city + ")";
}
}

if(dayType == nonworking || dayType == absence || dayType == annualLeave || dayType == maternityLeave)
{

var dayTypeFetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<attribute name='statuscode' />
<attribute name='tt_startdate' />
<attribute name='tt_workinghours' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
<filter type='or'>
<condition attribute='tt_daytype' operator='eq' value='` + nonworking + `' />
<condition attribute='tt_daytype' operator='eq' value='` + absence + `' />
<condition attribute='tt_daytype' operator='eq' value='` + annualLeave + `' />
<condition attribute='tt_daytype' operator='eq' value='` + maternityLeave + `' />
</filter>
</filter>
</entity>
</fetch>`

const dayTypefetchResult = await GetDataFromDataverse("tt_calendars", dayTypeFetchxml);

var numberOfNonWorkingRecords = dayTypefetchResult.length;
if(numberOfNonWorkingRecords == 0)
{
const createResponse = await AddDataToDataverse("tt_calendars", payload);
if(createResponse){
workingPeriodLog.text(`${x} out of ${recordsToAdd} days added.`);
//Relaod the Page once all records are created
if(recordsToAdd-1 == x){
RefreshPowerBIDataset("Practice Gateway Calendar");
workingPeriodLog.text(`All days added. Refreshing the Calendar...`);
window.top.location.reload();
}
}
}
}
else if(dayType == working){
var hoursFullDay = 206340000
var hoursAM = 206340001
var hoursPM = 206340002

var workingHoursFetchxml = ``;

switch(parseInt(workingHours))
{
case 206340000:
workingHoursFetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
<condition attribute='tt_daytype' operator='eq' value='` + working + `' />
</filter>
</entity>
</fetch>`
break;
case hoursAM:
workingHoursFetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='{{CalendarContactID}}' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
<condition attribute='tt_daytype' operator='eq' value='` + working + `' />
<filter type='or'>
<condition attribute='tt_workinghours' operator='eq' value='` + hoursFullDay + `' />
<condition attribute='tt_workinghours' operator='eq' value='` + hoursAM + `' />
</filter>
</filter>
</entity>
</fetch>`
break;
case hoursPM:
workingHoursFetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
<condition attribute='tt_daytype' operator='eq' value='` + working + `' />
<filter type='or'>
<condition attribute='tt_workinghours' operator='eq' value='` + hoursFullDay + `' />
<condition attribute='tt_workinghours' operator='eq' value='` + hoursPM + `' />
</filter>
</filter>
</entity>
</fetch>`
break;
default:
workingHoursFetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
<condition attribute='tt_daytype' operator='eq' value='` + working + `' />
</filter>
</entity>
</fetch>`
}
const workingHoursfetchResult = await GetDataFromDataverse("tt_calendars", workingHoursFetchxml);

var numberOfNonWorkingHourRecords = workingHoursfetchResult.length;
if(numberOfNonWorkingHourRecords == 0)
{
const createResponse = await AddDataToDataverse("tt_calendars", payload);
if(createResponse){
workingPeriodLog.text(`${x} out of ${recordsToAdd} days added.`);
//Relaod the Page once all records are created
if(recordsToAdd-1 == x){
RefreshPowerBIDataset("Practice Gateway Calendar");
workingPeriodLog.text(`All days added. Refreshing the Calendar...`);
window.top.location.reload();
}
}
}
}
else{
const createResponse = await AddDataToDataverse("tt_calendars", payload);

if(createResponse){
workingPeriodLog.text(`${x} out of ${recordsToAdd} days added.`);
//Relaod the Page once all records are created
if(recordsToAdd-1 == x){
RefreshPowerBIDataset("Practice Gateway Calendar");
workingPeriodLog.text(`All days added. Refreshing the Calendar...`);
window.top.location.reload();
}
}
}
}
window.top.location.reload();
}

}
}
};

async function AddNewRecords(startDate,endDate,country,state,city,inCountryAtMidnight,dayType,workingHours,otherDetails,notes,overwriteData)
{

let iframeid = 'CreateFrame';
let iframelogid = "creationLog";
let overwiteresponse = false;

if(overwriteData) {
console.log("calling function: overwriteExistingData - AddNewRecords");
overwiteresponse = await overwriteExistingData(startDate, endDate, iframeid, iframelogid)
console.log("function completed: overwriteExistingData - AddNewRecords");
}

if( !overwriteData || overwiteresponse == true ) {

var iframe = document.getElementById(iframeid);
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var creationLog = $(iframeDocument).find('span[id="' + iframelogid + '"]');

var eventType = 206340000;
var contactid = "{{CalendarContactID}}";
var oneDayInSeconds = 86400000;

let end = Date.parse(endDate)
end = end.getTime() / oneDayInSeconds;
let current = Date.parse(startDate)
current = current.getTime() / oneDayInSeconds

var remainder = end - current;

//Day Types
var working = 206340000;
var nonworking = 206340001;
var absence = 206340002;
var annualLeave = 206340003;
var travelling = 206340004;
var other = 206340005;
var maternityLeave = 206340006;

//Status Code
var submitted = 206340001;

var datesToAdd = [];
//Iterate through all dates in the form
creationLog.text(`Validating days to create.`);

for(var d = Date.parse(startDate); d <= Date.parse(endDate); d.setDate(d.getDate()+ 1))
{
let formattedstartDate = Date.parse(d).format("MM/dd/yyyy");
//Add to Dates to Add array
datesToAdd.push(formattedstartDate);
}

let formattedstartDate = Date.parse(startDate).format("MM/dd/yyyy");
let formattedendDate = Date.parse(endDate).format("MM/dd/yyyy");

var submittedfetchxml = `<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='tt_calendar'><attribute name='tt_calendarid' /><attribute name='tt_name' /><attribute name='tt_workinghours' /><attribute name='statuscode' /><attribute name='tt_startdate' /><order attribute='tt_name' descending='false' /><filter type='and'><condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' /><condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' /><condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' /><condition attribute='statuscode' operator='eq' value='` + submitted + `' /><filter type='or'><condition attribute='tt_daytype' operator='ne' value='` + travelling + `' /><condition attribute='statuscode' operator='eq' value='` + submitted + `' /></filter></filter></entity></fetch>`

creationLog.text(`Checking for already submitted dates in selected range.`);
const submittedfetchResult = await GetDataFromDataverse("tt_calendars", submittedfetchxml);
console.log(submittedfetchResult)

if(submittedfetchResult){
for(var i = 0; i < submittedfetchResult.length; i++)
{
var submittedresponseStartDate = Date.parse(submittedfetchResult[i].tt_startdate).format("MM/dd/yyyy")
var index = datesToAdd.indexOf(submittedresponseStartDate);
if (index > -1) {
datesToAdd.splice(index, 1); // Remove the date at the found index
}
}
}

if(datesToAdd.length == 0)
{
window.top.location.reload();
}

var hoursFullDay = 206340000
var hoursAM = 206340001
var hoursPM = 206340002

var dayTypeFetchxml = `<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='tt_calendar'><attribute name='tt_calendarid' /><attribute name='tt_name' /><attribute name='statuscode' /><attribute name='tt_startdate' /><attribute name='tt_workinghours' /><order attribute='tt_name' descending='false' /><filter type='and'><condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' /><condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' /><condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' /><filter type='or'><condition attribute='tt_daytype' operator='eq' value='` + nonworking + `' /><condition attribute='tt_daytype' operator='eq' value='` + absence + `' /><condition attribute='tt_daytype' operator='eq' value='` + annualLeave + `' /><condition attribute='tt_daytype' operator='eq' value='` + maternityLeave + `' /></filter></filter></entity></fetch>`

const dayTypefetchResult = await GetDataFromDataverse("tt_calendars", dayTypeFetchxml);

var workingHoursFullDayFetchxml = `<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='tt_calendar'><attribute name='tt_calendarid' /><attribute name='tt_name' /><order attribute='tt_name' descending='false' /><filter type='and'><condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' /><condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' /><condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' /><condition attribute='tt_daytype' operator='eq' value='` + working + `' /></filter></entity></fetch>`

const workingHoursFullDayfetchResult = await GetDataFromDataverse("tt_calendars", workingHoursFullDayFetchxml);

var workingHoursAMFetchxml = `<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='tt_calendar'><attribute name='tt_calendarid' /><attribute name='tt_name' /><order attribute='tt_name' descending='false' /><filter type='and'><condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' /><condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' /><condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' /><condition attribute='tt_daytype' operator='eq' value='` + working + `' /><filter type='or'><condition attribute='tt_workinghours' operator='eq' value='` + hoursFullDay + `' /><condition attribute='tt_workinghours' operator='eq' value='` + hoursAM + `' /></filter></filter></entity></fetch>`

const workingHoursAMfetchResult = await GetDataFromDataverse("tt_calendars", workingHoursAMFetchxml);

var workingHoursPMFetchxml = `<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='tt_calendar'><attribute name='tt_calendarid' /><attribute name='tt_name' /><order attribute='tt_name' descending='false' /><filter type='and'><condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' /><condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' /><condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' /><condition attribute='tt_daytype' operator='eq' value='` + working + `' /><filter type='or'><condition attribute='tt_workinghours' operator='eq' value='` + hoursFullDay + `' /><condition attribute='tt_workinghours' operator='eq' value='` + hoursPM + `' /></filter></filter></entity></fetch>`

const workingHoursPMfetchResult = await GetDataFromDataverse("tt_calendars", workingHoursPMFetchxml);

const payloads = [];

var recordsToAdd = datesToAdd.length;
for(var x = 0; x < recordsToAdd; x++)
{
var recordDate = Date.parse(datesToAdd[x]).format("yyyy-MM-ddT10:00:00.0000000")
var formattedrecordDate = Date.parse(datesToAdd[x]).format("MM/dd/yyyy")

var payload = {
"tt_LocationCountry@odata.bind": "/tt_countries(" + country + ")",
"tt_eventtype" : eventType,
"tt_startdate": recordDate,
"tt_enddate": recordDate,
"tt_Contact@odata.bind": "/contacts(" + contactid + ")",
"tt_incountryatmidnight" : inCountryAtMidnight,
"tt_daytype": dayType,
"tt_notes": notes
}
if(dayType == working) {
payload["tt_workinghours"] = workingHours;
}
else if (dayType == other || dayType == travelling) {
payload["tt_daytypeother"] = otherDetails;
}

if(state != "" && state != null) {
payload["tt_LocationState@odata.bind"] = "/tt_states(" + state + ")";
if(city != "" && city != null) {
payload["tt_LocationCity@odata.bind"] = "/tt_cities(" + city + ")";
}
}
//Add a Dataverse Record

if(dayType == nonworking || dayType == absence || dayType == annualLeave || dayType == maternityLeave)
{
if (dayTypefetchResult) {
const dayTyperecordExists = dayTypefetchResult.some(record => {
const dayTyperesponseStartDate = new Date(record.tt_startdate).format("MM/dd/yyyy");
return dayTyperesponseStartDate === formattedrecordDate;
});

if (!dayTyperecordExists) {
payloads.push(payload);
}
}
}
else if(dayType == working) {
if(parseInt(workingHours) == hoursFullDay){
if (workingHoursFullDayfetchResult) {
const workingHoursFullDayExists = workingHoursFullDayfetchResult.some(record => {
const workingHoursFullDayResponseStartDate = new Date(record.tt_startdate).format("MM/dd/yyyy");
return workingHoursFullDayResponseStartDate === formattedrecordDate;
});

if (!workingHoursFullDayExists) {
payloads.push(payload);
}
}
}
else if(parseInt(workingHours) == hoursAM){
if (workingHoursAMfetchResult) {
const workingHoursAMExists = workingHoursAMfetchResult.some(record => {
const workingHoursAMResponseStartDate = new Date(record.tt_startdate).format("MM/dd/yyyy");
return workingHoursAMResponseStartDate === formattedrecordDate;
});

if (!workingHoursAMExists) {
payloads.push(payload);
}
}
}
else if(parseInt(workingHours) == hoursPM){
if (workingHoursPMfetchResult) {
const workingHoursPMExists = workingHoursPMfetchResult.some(record => {
const workingHoursPMResponseStartDate = new Date(record.tt_startdate).format("MM/dd/yyyy");
return workingHoursPMResponseStartDate === formattedrecordDate;
});

if (!workingHoursPMExists) {
payloads.push(payload);
}
}
}
}
else{
payloads.push(payload);
}
}

console.log(`payloads`)
console.log(payloads)

let recordsToCreate = payloads.length - 1
if(payloads.length > 0) {
for(var k = 0; k < payloads.length; k++)
{
const createResponse = await AddDataToDataverse("tt_calendars", payloads[k]);
if(createResponse){
creationLog.text(`${k} out of ${recordsToAdd} days added.`);
//Relaod the Page once all records are created
if(recordsToCreate == k){
RefreshPowerBIDataset("Practice Gateway Calendar");
creationLog.text(`All days added. The page will now reload.`);
window.top.location.reload();
}
}
}
}
else {
window.top.location.reload();
}
}
};

async function submitDates(recordIDs){

var iframe = document.getElementById('SubmissionFrame');
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var submissionLog = $(iframeDocument).find('span[id="submissionLog"]');

var RecordsToSubmit = recordIDs.length

for(var i = 0; i < RecordsToSubmit; i++)
{

const submissionResponse = await SubmitCalendarRecordsDataverse("tt_calendars", recordIDs[i])
if(submissionResponse)
{
submissionLog.text(`${i} out of ${RecordsToSubmit} entries submitted.`);
if(RecordsToSubmit-1 == i){
RefreshPowerBIDataset("Practice Gateway Calendar");
submissionLog.text(`All entries submitted. Refreshing the Calendar...`);
window.top.location.reload();
}
}
}
};

function setUpWorkingPattern(){
var frameSource = "/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141?entityformid=" + setupForm + "&languagecode=1033";
$('div#workingPatternModal').find('iframe').attr("src", frameSource);
$("#workingPatternModal").modal();
};

function DeleteDatesForm(){
var frameSource = "/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141?entityformid=" + deletionForm + "&languagecode=1033";
$('div#DeletionModal').find('iframe').attr("src", frameSource);
$("#DeletionModal").modal();
};

function SubmitDatesForm(){
var frameSource = "/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141?entityformid=" + submissionForm + "&languagecode=1033";
$('div#submissionModal').find('iframe').attr("src", frameSource);
$("#submissionModal").modal();
};

function CreateRecord(date){
var today = new Date();
localStorage.setItem("inputDate", today.format("yyyy-MM-dd"));
if(date != null){
localStorage.setItem("inputDate", date);
}
var frameSource = "/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141?entityformid=" + createForm + "&languagecode=1033";
$('div#CreateModal').find('iframe').attr("src", frameSource);
$("#CreateModal").modal();
};

function EditRecord(recordID){
var frameSource = "/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141?id=" + recordID + "&entityformid=" + editForm + "&languagecode=1033";
$('div#EditModal').find('iframe').attr("src", frameSource);
$("#EditModal").modal();
};

var lastClick = 0;
var delay = 20;
var cancelled = false;

function SelectModal(eventTrigger, inputValue)
{
cancelled = false;
//Delay added as both the event and day cell are clickable, and will throw 2 triggers when the event is clicked. This prevents multiple function calls.
if (lastClick >= (Date.now() - delay))
{
return;
}
lastClick = Date.now();
var elem = eventTrigger
switch(elem){
case "A":
EditRecord(inputValue);
break;
case "DIV":
CreateRecord(inputValue);
break;
default:
CreateRecord(inputValue);
}
};


function RefreshModal(modalID){
cancelled = true;
$('div#' + modalID).find('iframe').attr("src", $('div#' + modalID).find('iframe').attr("src"));
};

function reloadWindow(buttonid, frameid) {
var btnid = buttonid;
var fraid = frameid;
var iframe = document.getElementById(frameid);
var frameButton = iframe.contentWindow.document.getElementById(buttonid);

if(cancelled == false)
{
if($(frameButton).length == 0)
{
RefreshPowerBIDataset("Practice Gateway Calendar");
window.top.location.reload();
}
else{
setTimeout( function(){ reloadWindow(btnid, fraid) }, 1000 );
}
}
};

function RefreshPowerBIDataset(dataset)
{
var reloadCalendarurl = "{{refreshPowerBIUrl}}";

$.ajax({
url: reloadCalendarurl,
type: "POST",
headers: {"Accept": "application/json",
"Content-Type": "application/json"
},
data: '{"Dataset": "' + dataset + '"}',
success: function(data) {
console.log("Refreshed")
},
error: function(data) {
//
}
});
};

async function checkValidDeletion(startDate, endDate)
{

var iframe = document.getElementById('DeletionFrame');
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var deletionLog = $(iframeDocument).find('span[id="deletionLog"]');

var contactid = "{{ CalendarContactID }}";
var oneDayInSeconds = 86400000;
var RecordsToDelete = 0;

let end = Date.parse(endDate)
var formattedendDate = Date.parse(end).format("MM/dd/yyyy")
let start = Date.parse(startDate)
var formattedstartDate = Date.parse(start).format("MM/dd/yyyy")

var fetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<attribute name='statuscode' />
<attribute name='tt_startdate' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='statuscode' operator='eq' value='1' />
<condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' />
<condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' />
</filter>
</entity>
</fetch>`

deletionLog.text(`Validating days to delete.`);
const deletionfetchResult = await GetDataFromDataverse("tt_calendars", fetchxml);
var RecordsToDelete = deletionfetchResult.length;
if(RecordsToDelete == 0)
{
window.top.location.reload();
}

for (let i = 0; i < RecordsToDelete; i++) {

var recordID = deletionfetchResult[i].tt_calendarid;

const deletionResponse = await DeleteFromDataverse("tt_calendars", recordID);

if(deletionResponse){
deletionLog.text(`${i} out of ${RecordsToDelete} entries deleted.`);
//Relaod the Page once all records are created
if(RecordsToDelete-1 == i){
RefreshPowerBIDataset("Practice Gateway Calendar");
deletionLog.text(`All entries deleted. Refreshing the Calendar...`);
window.top.location.reload();
}
}
}
};

async function overwriteExistingData(startDate, endDate, iframeid, iframelogid)
{
console.log("running function: overwriteExistingData");
var iframe = document.getElementById(iframeid);
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var deletionLog = $(iframeDocument).find('span[id="' + iframelogid + '"]');

var contactid = "{{ CalendarContactID }}";
var oneDayInSeconds = 86400000;
var RecordsToDelete = 0;

let end = Date.parse(endDate)
var formattedendDate = Date.parse(end).format("MM/dd/yyyy")
let start = Date.parse(startDate)
var formattedstartDate = Date.parse(start).format("MM/dd/yyyy")

var fetchxml = `
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<attribute name='statuscode' />
<attribute name='tt_startdate' />
<order attribute='tt_name' descending='false' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='statuscode' operator='eq' value='1' />
<condition attribute='tt_startdate' operator='on-or-after' value='` + formattedstartDate + `' />
<condition attribute='tt_startdate' operator='on-or-before' value='` + formattedendDate + `' />
</filter>
</entity>
</fetch>`

deletionLog.text(`Validating days to delete.`);
const deletionfetchResult = await GetDataFromDataverse("tt_calendars", fetchxml);
var RecordsToDelete = deletionfetchResult.length;
if(RecordsToDelete == 0)
{
return true;
}

for (let i = 0; i < RecordsToDelete; i++) {

var recordID = deletionfetchResult[i].tt_calendarid;

const deletionResponse = await DeleteFromDataverse("tt_calendars", recordID);

if(deletionResponse){
deletionLog.text(`${i} out of ${RecordsToDelete} entries deleted.`);
//Relaod the Page once all records are created
if(RecordsToDelete-1 == i){
deletionLog.text(`All entries deleted. Adding new Data...`);
return true;
}
}
}
};

async function checkValidSubmission(startDate, endDate)
{
var contactid = "{{ CalendarContactID }}";
var oneDayInSeconds = 86400000;
var recordIDs = [];
var daysMissingRecords = [];

let end = Date.parse(endDate)
end = end.getTime() / oneDayInSeconds;
let current = Date.parse(startDate)
current = current.getTime() / oneDayInSeconds
var remainder = end - current;

var iframe = document.getElementById('SubmissionFrame');
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var submissionLog = $(iframeDocument).find('span[id="submissionLog"]');
submissionLog.text(`Validating days to submit.`);

for(var d = Date.parse(startDate); d <= Date.parse(endDate); d.setDate(d.getDate()+ 1))
{
var recordDate = Date.parse(d).format("MM/dd/yyyy")
daysMissingRecords.push(recordDate);

var fetchxml = `
<fetch mapping='logical'>
<entity name='tt_calendar'>
<attribute name='tt_calendarid' />
<attribute name='tt_name' />
<attribute name='tt_incountryatmidnight' />
<attribute name='tt_startdate' />
<attribute name='tt_contact' />
<filter type='and'>
<condition attribute='tt_contact' operator='eq' uitype='contact' value='` + contactid + `' />
<condition attribute='tt_startdate' operator='on' value='` + recordDate + `' />
</filter>
</entity>
</fetch>`

const submissionfetchResult = await GetDataFromDataverse("tt_calendars", fetchxml);

if(submissionfetchResult.length > 0)
{
for (let i = 0; i < submissionfetchResult.length; i++) {
submissionLog.text(`${remainder} days left to validate.`);

//Get Date Value
var datetoRemove = Date.parse(submissionfetchResult[i].tt_startdate).format("MM/dd/yyyy")
var MidnightChecked = submissionfetchResult[i].tt_incountryatmidnight;
//Add Record to Array
recordIDs.push(submissionfetchResult[i].tt_calendarid)
if(MidnightChecked){
let index = daysMissingRecords.indexOf(datetoRemove);
if (index > -1) { // only splice array when item is found
daysMissingRecords.splice(index, 1); // 2nd parameter means remove one item only
}
}
}
}
remainder--;
if(remainder < 0)
{
if(daysMissingRecords.length > 0)
{
return new Promise((resolve) => {
setTimeout(() => {
resolve(daysMissingRecords);
}, 10);
});
}
else
{
return new Promise((resolve) => {
setTimeout(() => {
resolve(recordIDs);
}, 10);
});
}
}

}
//return daysMissingRecords
};

</script>

Calendar - Modals

Source
<!-- Edit Modal -->
<div class="modal fade" id="EditModal" role="dialog">
<div class="modal-dialog modal-lg" id="myModal">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" onclick="RefreshModal('EditModal')"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title"><span class="fa fa-edit" aria-hidden="true"></span> Edit Event </h4>
</div>
<div class="modal-body">
{{snippets["Calendar/editForm/Information"]}}
<iframe id="EditFrame" data-page="/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141" src="" style="width: 100%;border: none;height: 700px;" title=" Edit"></iframe>
</div>
</div>
</div>
</div>
<!-- Edit Modal -->

<!-- Create Modal -->
<div class="modal fade" id="CreateModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" onclick="RefreshModal('CreateModal')"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title"><span class="fa fa-pencil-square-o" aria-hidden="true"></span> Create Event </h4>
</div>
<div class="modal-body">
{{snippets["Calendar/createForm/Information"]}}
<iframe id="CreateFrame" data-page="/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141" src="" style="width: 100%;border: none;height: 700px;"></iframe>
</div>
</div>
</div>
</div>
<!-- Create Modal -->

<!-- Start Modal -->
<div class="modal fade" id="workingPatternModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" onclick="RefreshModal('workingPatternModal')"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title"><span class="fa fa-pencil-square-o" aria-hidden="true"></span> Set a Working Pattern </h4>
</div>
<div class="modal-body">
{{snippets["Calendar/setupForm/Information"]}}
<iframe id="setupFrame" data-page="/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141" src="" style="width: 100%;border: none;height: 700px;"></iframe>
</div>
</div>
</div>
</div>
<!-- Start Modal -->

<!-- Submission Modal -->
<div class="modal fade" id="submissionModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" onclick="RefreshModal('submissionModal')"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title"><span class="fa fa-pencil-square-o" aria-hidden="true"></span> Submit Dates to Your Advisor </h4>
</div>
<div class="modal-body">
{{snippets["Calendar/submissionForm/Information"]}}
<iframe id="SubmissionFrame" data-page="/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141" src="" style="width: 100%;border: none;height: 700px;"></iframe>
</div>
</div>
</div>
</div>
<!-- Submission Modal -->

<!-- Deletion Modal -->
<div class="modal fade" id="DeletionModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" onclick="RefreshModal('DeletionModal')"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title"><span class="fa fa-pencil-square-o" aria-hidden="true"></span> Delete Non-Submitted Data </h4>
</div>
<div class="modal-body">
{{snippets["Calendar/deletionForm/Information"]}}
<iframe id="DeletionFrame" data-page="/_portal/modal-form-template-path/d78574f9-20c3-4dcc-8d8d-85cf5b7ac141" src="" style="width: 100%;border: none;height: 700px;"></iframe>
</div>
</div>
</div>
</div>
<!-- Deletion Modal -->

Calendar - Setup

Source
{% fetchxml existingRecordDates %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="tt_calendar">
<attribute name="tt_calendarid" />
<attribute name="tt_startdate" />
<attribute name="tt_eventtype" />
<attribute name="tt_daytype" />
<order attribute="tt_startdate" descending="false" />
<filter type="and">
<condition attribute="statuscode" operator="ne" value="206340001" />
<condition attribute="tt_eventtype" operator="eq" value="206340000" />
<condition attribute="tt_contact" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% assign incompleteDates = "" %}
{% assign processedDates = "" %}

{% if existingRecordDates.results.entities.size >= 1 %}
{% assign dateRecords = existingRecordDates.results.entities.size | minus: 1 %}
{% for i in (0...dateRecords) %}
{% assign existingDate = existingRecordDates.results.entities[i].tt_startdate %}
{% fetchxml RecordsFromDate%}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="tt_calendar">
<attribute name="tt_calendarid" />
<attribute name="tt_startdate" />
<attribute name="tt_eventtype" />
<attribute name="tt_daytype" />
<attribute name="tt_workinghours" />
<order attribute="tt_startdate" descending="false" />
<order attribute="tt_workinghours" descending="false" />
<filter type="and">
<condition attribute="tt_eventtype" operator="eq" value="206340000" />
<condition attribute="tt_contact" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
<condition attribute="tt_startdate" operator="on" value="{{existingDate}}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% if RecordsFromDate.results.entities.size == 1 %}
{% assign dayType = RecordsFromDate.results.entities[0].tt_daytype.label %}
{% assign workingHours = RecordsFromDate.results.entities[0].tt_workinghours.label %}
{% assign dateStart = RecordsFromDate.results.entities[0].tt_startdate | date: "dd-MM-yyyy" %}
{% if dayType == "Working" %}
{% if workingHours == "AM" %}
{% assign incompleteDates = incompleteDates | append: {{dateStart}} | append: " does not have a record for PM" | append:',' %}
{% endif %}
{% if workingHours == "PM" %}
{% assign incompleteDates = incompleteDates | append: {{dateStart}} | append: " does not have a record for AM" | append:',' %}
{% endif %}
{% endif %}
{% endif %}

{% if RecordsFromDate.results.entities.size >= 2 %}
{% assign formattedDate = existingDate | date: "dd-MM-yyyy"%}
{% unless processedDates contains formattedDate %}
{% assign recordDates = RecordsFromDate.results.entities.size | minus: 1 %}
{% assign dayTypeList = "" %}
{% assign workingHoursList = "" %}
{% for i in (0...recordDates) %}
{% assign dayType = RecordsFromDate.results.entities[i].tt_daytype.label %}
{% assign workingHours = RecordsFromDate.results.entities[i].tt_workinghours.label %}
{% assign dateStart = RecordsFromDate.results.entities[i].tt_startdate | date: "dd-MM-yyyy" %}
{% if dayType == "Working" %}
{% if workingHoursList contains workingHours %}
{% assign incompleteDates = incompleteDates | append: {{dateStart}} | append: " has multiple records for " | append: {{workingHours}} | append:',' %}
{% endif %}
{% unless workingHoursList contains workingHours %}
{% assign workingHoursList = workingHoursList | append:',' | append: workingHours %}
{% endunless %}
{% else%}
{% if dayTypeList contains dayType %}
{% assign incompleteDates = incompleteDates | append: {{dateStart}} | append: " has multiple records for " | append: {{dayType}} | append:',' %}
{% endif %}
{% unless dayTypeList contains dayType %}
{% assign dayTypeList = dayTypeList | append:',' | append: dayType %}
{% endunless %}
{% endif %}
{% endfor %}
{% if workingHoursList contains 'Full Day' %}
{% if workingHoursList contains 'AM' OR workingHoursList contains 'PM' %}
{% assign incompleteDates = incompleteDates | append: {{dateStart}} | append: " has too many working hours listed " | append:',' %}
{% endif %}
{% endif %}
{% assign processedDates = processedDates | append:',' | append: formattedDate %}
{% endunless %}
{% endif %}
{% endfor %}
{% endif %}



{% if incompleteDates.size > 0 %}
<script language="javascript">
$( document ).ready(function() {
$('#submissionButton').addClass("disabled");
});
</script>
{% assign notificationitems = incompleteDates | split: ',' %}
{% assign listsize = notificationitems.size | minus: 1 %}
<div class="alert alert-error alert-danger alert-block" id="calendarErrorBox">
<button class="close" style="float:right;" type="button" onclick="this.parentElement.style.display='none';"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<span class="fa fa-exclamation-circle" aria-hidden="true"></span>
<span class="xrm-attribute-value-encoded xrm-attribute-value">The following dates require your attention before any entries can be submitted:</span>
<ul role="presentation">
{% for i in (0...listsize) %}
<li>{{notificationitems[i]}}</li>
{% endfor %}
</ul>
</div>
{% endif %}

{% fetchxml UnitedKingdom %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="tt_country">
<attribute name="tt_countryid" />
<attribute name="tt_name" />
<attribute name="tt_countrycode" />
<order attribute="tt_name" descending="false" />
<filter type="and">
<condition attribute="tt_name" operator="eq" value="United Kingdom" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% fetchxml GetLastLocation %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="contact">
<attribute name="fullname" />
<attribute name="emailaddress1" />
<attribute name="tt_clientcode" />
<attribute name="tt_managername" />
<attribute name="ownerid" />
<attribute name="contactid" />
<attribute name="tt_lastlocation" />
<order attribute="fullname" descending="false" />
<filter type="and">
<condition attribute="contactid" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% if GetLastLocation.results.entities.size == 1 %}
{% assign LastLocationCode = GetLastLocation.results.entities[0].tt_lastlocation %}
{% fetchxml CountryCode %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="tt_country">
<attribute name="tt_countrycode" />
<attribute name="tt_countryid" />
<attribute name="tt_name" />
<filter type="and">
<condition attribute="tt_geolocationcode" operator="eq" value="{{LastLocationCode}}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}
{% endif %}

{% if CountryCode.results.entities.size == 1 %}
{% assign unitedKingdomID = CountryCode.results.entities[0].tt_countryid %}
{% assign unitedKingdomName = CountryCode.results.entities[0].tt_name %}
{% else %}
{% if UnitedKingdom.results.entities.size == 1 %}
{% assign unitedKingdomID = UnitedKingdom.results.entities[0].tt_countryid %}
{% assign unitedKingdomName = UnitedKingdom.results.entities[0].tt_name %}
{% endif %}
{% endif %}

Calendar - Shared

Source
{% extends 'Layout 1 Column Wide' %}

{% block header %}
{% include 'Breadcrumbs' %}
{% endblock %}

{% block main %}

{% include 'WrapperAJAX' %}

{% assign CalendarContactID = params.id %}

{% include 'Calendar - Setup' %}

{% include 'Calendar - Shared - Contact' %}

{% include 'Calendar - Modals' %}

{% include 'Calendar - JavaScript' %}

{% include 'Utilities' %}

<style>
#WeekViewToggleButton{
display:none;
}
</style>

{% endblock %}

Calendar - Shared - Contact

Source
{% fetchxml calendarContact %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="contact">
<attribute name="fullname" />
<attribute name="contactid" />
<filter type="and">
<condition attribute="contactid" operator="eq" uitype="contact" value="{{ CalendarContactID }}" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

{% if calendarContact.results.entities.size == 1 %}
{% assign contactFullName = calendarContact.results.entities[0].fullname %}
{% else %}
{% assign contactFullName = "Contact Not Found" %}
{% endif %}

{% comment %} Information {% endcomment %}
{{snippets["Calendar/Information"]}}

<h1 style="font-weight:bold;"> Calendar for {{contactFullName}} </h1>

{% fetchxml connectionCalendar %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="tt_calendar">
<attribute name="tt_calendarid" />
<attribute name="tt_name" />
<attribute name="createdon" />
<order attribute="tt_name" descending="false" />
<filter type="and">
<condition attribute="tt_contact" operator="eq" uitype="contact" value="{{CalendarContactID}}" />
</filter>
<link-entity name="contact" from="contactid" to="tt_contact" link-type="inner" alias="ac">
<link-entity name="connection" from="record1id" to="contactid" link-type="inner" alias="ad">
<filter type="and">
<condition attribute="record2id" operator="eq" uitype="contact" value="{{user.id}}" />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>
{% endfetchxml %}

{% assign contactRecords = "" %}
{% assign records = connectionCalendar.results.entities.size | minus: 1 %}
{% for i in (0...records) %}
{% assign recordid = connectionCalendar.results.entities[i].tt_calendarid %}
{% assign contactRecords = contactRecords | append: ',' | append: recordid %}
{% endfor %}

<script language="javascript">
var contactsRecords = "{{contactRecords}}";
</script>

{% fetchxml connectionContactDataApprover %}
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="connection">
<attribute name="record2id" />
<attribute name="record2roleid" />
<attribute name="connectionid" />
<filter type="and">
<condition attribute="record1id" operator="eq" uitype="contact" value="{{ user.id }}" />
<condition attribute="record2id" operator="eq" uitype="contact" value="{{params.id}}" />
<condition attribute="record2roleidname" operator="eq" uitype="connectionrole" value="Calendar - Data Approver" />
</filter>
</entity>
</fetch>
{% endfetchxml %}

<div id="calendarGrid">

<div class="btn-group pull-right">
<a id="addNew" class="btn btn-primary" title="Add New" role="button" onclick="SelectModal(null,null)">Add New</a>
<a id="startButton" class="btn btn-primary" title="Add Working Period" role="button" onclick="setUpWorkingPattern()">Add Working Period</a>
{% if connectionContactDataApprover.results.entities.size >= 1 %}
<a id="submissionButton" class="btn btn-primary" title="Submit Dates" role="button" onclick="SubmitDatesForm()">Submit Dates</a>
{% endif %}
<a id="deletionButton" class="btn btn-secondary" title="Delete" role="button" onclick="DeleteDatesForm()">Delete</a>
</div>

<div class="btn-group pull-right" style="padding-right: 5%;">
<a id="tt_calendarHelp" class="btn btn-info" style="padding:5px 5px;font-size:20px;line-height:1;border-radius:10px;" onclick="$('#calendarHelpBox').show()">
<span class="glyphicon glyphicon-info-sign"></span>
</a>
</div>

<br>

{% include "entity_list" key:"Connection Calendar - Calendar View" %}

</div>